activiti和设计模式(2.1)

activiti中Command的执行的过程,也是一个设计模式来进行控制的,就是责任链设计模式,或者:Interpreter pattern.

首先是启动的代码:

//调用方:
ProcessInstance ins = runtimeService.startProcessInstanceById(workFlowId, formId,variablesObject);      

//调用的入口:
public ProcessInstance startProcessInstanceById(String processDefinitionId,
    String businessKey, Map<String, Object> variables) {
    return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(null,
        processDefinitionId, businessKey, variables));
  }

debug页面

从图中可以看出:CommandExecutor 已经包含了执行所需要的全部的内容,我们看一下执行的代码:

@Override
 public <T> T execute(Command<T> command) {
   return execute(defaultConfig, command);
 }

 @Override
  public <T> T execute(CommandConfig config, Command<T> command) {
    return first.execute(config, command);
  }
  //这里我们可以看到,执行的过程进入了某一个链中。

这个链总共有三个类构成:
org.activiti.engine.impl.interceptor.LogInterceptor
org.activiti.engine.impl.interceptor.CommandContextInterceptor
org.activiti.engine.impl.interceptor.CommandInvoker

这三个类全部实现了接口:CommandInterceptor

public interface CommandInterceptor {

  <T> T execute(CommandConfig config, Command<T> command);
  CommandInterceptor getNext();
  void setNext(CommandInterceptor next);
}

通过这个代码的 setNext方法,这三个类构成了一个执行链,在引擎初始化的时候,能够发现这个执行链构造和初始化的代码:

protected void initCommandInvoker() {
  if (commandInvoker==null) {
    commandInvoker = new CommandInvoker();//③
  }
}

protected void initCommandInterceptors() {
    if (commandInterceptors==null) {
      commandInterceptors = new ArrayList<CommandInterceptor>();
      if (customPreCommandInterceptors!=null) {
        commandInterceptors.addAll(customPreCommandInterceptors);
      }
      commandInterceptors.addAll(getDefaultCommandInterceptors());
      if (customPostCommandInterceptors!=null) {
        commandInterceptors.addAll(customPostCommandInterceptors);
      }
      commandInterceptors.add(commandInvoker);
    }
  }

protected Collection< ? extends CommandInterceptor> getDefaultCommandInterceptors() {
   List<CommandInterceptor> interceptors = new ArrayList<CommandInterceptor>();
   interceptors.add(new LogInterceptor());//①

   CommandInterceptor transactionInterceptor = createTransactionInterceptor();
   if (transactionInterceptor != null) {
     interceptors.add(transactionInterceptor);
   }

   interceptors.add(new CommandContextInterceptor(commandContextFactory, this));//②
   return interceptors;
 }

//初始化这条链
 protected CommandInterceptor initInterceptorChain(List<CommandInterceptor> chain) {
    if (chain==null || chain.isEmpty()) {
      throw new ActivitiException("invalid command interceptor chain configuration: "+chain);
    }
    for (int i = 0; i < chain.size()-1; i++) {
      chain.get(i).setNext( chain.get(i+1) );
    }
    return chain.get(0);
  }

  // commandExecutor 初始化完成
  protected void initCommandExecutor() {
     if (commandExecutor==null) {
       CommandInterceptor first = initInterceptorChain(commandInterceptors);
       commandExecutor = new CommandExecutorImpl(getDefaultCommandConfig(), first);
     }
   }

这个三个拦截链都做了什么呢?第一个就是日志记录,虽然个人感觉比较的无聊,但是也可能是一个扩展的示例:LogInterceptor

public <T> T execute(CommandConfig config, Command<T> command) {
    if (!log.isDebugEnabled()) {
      // do nothing here if we cannot log
      return next.execute(config, command);
    }
    log.debug("\n");
    log.debug("--- starting {} --------------------------------------------------------", command.getClass().getSimpleName());
    try {

      return next.execute(config, command);

    } finally {
      log.debug("--- {} finished --------------------------------------------------------", command.getClass().getSimpleName());
      log.debug("\n");
    }
  }

第二个链:CommandContextInterceptor 主要是构建命令运行的执行的环境:

public <T> T execute(CommandConfig config, Command<T> command) {
   CommandContext context = Context.getCommandContext();  
   boolean contextReused = false;
   // We need to check the exception, because the transaction can be in a rollback state,
   // and some other command is being fired to compensate (eg. decrementing job retries)
   if (!config.isContextReusePossible() || context == null || context.getException() != null) {
     context = commandContextFactory.createCommandContext(command);    	
   }  
   else {
     log.debug("Valid context found. Reusing it for the current command '{}'", command.getClass().getCanonicalName());
     contextReused = true;
   }
   try {
     // Push on stack
     Context.setCommandContext(context);
     Context.setProcessEngineConfiguration(processEngineConfiguration);
     return next.execute(config, command);
   } catch (Exception e) {
     context.exception(e);
   } finally {
     try {
       if (!contextReused) {
         context.close();
       }
     } finally {
       // Pop from stack
       Context.removeCommandContext();
       Context.removeProcessEngineConfiguration();
       Context.removeBpmnOverrideContext();
     }
   }
   return null;
 }

从这个环境构造,可以看出来两个问题:

  1. context的组织方式,是根据Command进行的,并且Context是通过stack进行组织的。
  2. 既然context是根据stack组织的,说明有压栈,出栈的操作,也就说明Command之间存在嵌套的可能性。

第三个链:CommandInvoker 命令行的执行:

@Override
  public <T> T execute(CommandConfig config, Command<T> command) {
    return command.execute(Context.getCommandContext());
  }

可以看到最终执行的过程,还是到了每一个的command类中,这也是符合预期的。此例中最终进入StartProcessInstanceCmd类中,执行代码:

public ProcessInstance execute(CommandContext commandContext) {
    DeploymentManager deploymentManager = commandContext
      .getProcessEngineConfiguration()
      .getDeploymentManager();

    // Find the process definition
    ProcessDefinitionEntity processDefinition = null;
    if (processDefinitionId != null) {
      processDefinition = deploymentManager.findDeployedProcessDefinitionById(processDefinitionId);
    }
    。。。。。。。。
    // Start the process instance
    ExecutionEntity processInstance = processDefinition.createProcessInstance(businessKey);
		。。。。。。。。
    processInstance.start();

    return processInstance;
  }

可以看出来这个是 Interpreter pattern 和 Command Pattern 联合使用的一种情况,就目的而言,试分析一二:
总结来自:

1)一个产品或者一个项目,很少是一个人开发出来的,大多都涉及到协同工作。但是既然是一个框架,那么总体上面的需要有一个规范,利于大家的开发,利于大家的协调。这个就是架构的意义所在。 有了具体的架构的约束,加入一些基础的组件,基本上能够把实现的大体的过程规划出来,这样这个框架的整体的风格也就确定了。就像Activiti做的这样,明确以Command作为基本开发模型,辅之以Event-Listener,这样编程风格的整体性得到了保证。

2)使用命令模式和责任链的好处 职责分离,解耦。有了Command,各个Service从角色上说只是一些协调者或者控制者,不需要知道具体怎么做,他只是把任务交给了各个命令。便于封装每一个的功能

3)解耦之后,随之带来的一个好处,就是扩展或者说灵活性的增加,我们可以把自己扩展的动作按照同样的方式,封装成一个一个的command,更加的便于理解和别人的使用。大大的增加activiti的生态。

Powered by andiHappy and Theme by AndiHappy